package com.codi.bus.core.service.impl;

import com.codi.base.exception.BaseAppException;
import com.codi.base.util.*;
import com.codi.bus.constant.GlobalConstant;
import com.codi.bus.constant.RuleConstant;
import com.codi.bus.core.dao.*;
import com.codi.bus.core.domain.*;
import com.codi.bus.core.resultModel.*;
import com.codi.bus.core.service.*;
import com.codi.bus.core.service.model.*;
import com.codi.bus.core.service.util.CalculateAssetsUtils;
import com.codi.bus.core.service.util.FundUtil;
import com.codi.bus.core.util.BaseResultUtil;
import com.codi.bus.exception.BaseException;
import com.codi.bus.exception.SystemDBException;
import com.codi.bus.util.LookupUtil;
import com.codi.fundData.domain.FundMMYieldPerformance;
import com.codi.fundData.domain.SecurityProduct;
import com.codi.fundData.service.FundMMYieldPerformanceService;
import com.codi.message.constant.ErrorConstant;
import com.codi.message.util.MessageUtil;
import com.codi.trade.service.TradeApplyQueryService;
import com.google.common.base.Preconditions;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.*;

import static java.math.BigDecimal.ROUND_HALF_DOWN;


/**
 * Created by asus on 2018/6/13.
 */
@Service("localAssetsService")
@Slf4j

public class LocalAssetsServiceImpl implements LocalAssetsService {

    @Autowired
    private ProfitDao profitDao;

    @Autowired
    private UserDao userDao;
    @Autowired
    private UserService userService;

    @Autowired
    private FundDetailService fundDetailService;

    @Autowired
    private FundDividentsDao fundDividentsDao;

    @Autowired
    private CdUserShareDao cdUserShareDao;

    @Autowired
    private QueryService queryService;

    @Autowired
    private LookupDao lookupDao;

    @Autowired
    private FundMMYieldPerformanceService fundMMYieldPerformanceService;

    @Autowired
    private TradeApplyQueryService tradeApplyQueryService;

    @Autowired
    private FundCombinationMappingDao fundCombinationMappingDao;

    @Autowired
    private UserBankDao userBankDao;

    @Autowired
    private PortfolioTradeAccoDao portfolioTradeAccoDao;

    @Autowired
    private UserShareService userShareService;

    @Autowired
    private LookupService lookupService;

    @Autowired
    private WalletService walletService;

    @Autowired
    private FundCombinationService fundCombinationService;

    @Autowired
    private ProfitService profitService;

    @Autowired
    private TradeOrdersDao tradeOrdersDao;

    // 获取所有基金资产

    /**
     * @param userId
     * @param requestNum
     * @param beginNum
     * @return
     * @throws BaseException
     * @throws BaseAppException
     */
    @Override
    public ShareListResult getAllShares(Long userId, Integer requestNum, Integer beginNum) throws BaseException, BaseAppException {
        User user = userService.getUser(userId);
        ShareListResult result = new ShareListResult();
        // 判断是否已开户
        if (user == null || StringUtil.isEmpty(user.getExternalClientId())) {
            result.setErrorCode(ErrorConstant.ERROR_NO_ACCOUNT);
            result.setSuccess(false);
            result.setErrorType(GlobalConstant.ERROR_TYPE_APPLICATION);
            return result;
        }
        Date netValueDate = DateUtils.addDay(new Date(), -1); //默认净值日期为前一天

        // 总持仓收益
        BigDecimal totalAccumIncome = new BigDecimal(0);
        log.debug("totalAccumIncome1:{}", totalAccumIncome);

        // 总本金
        BigDecimal totalFundBalance = new BigDecimal(0);
        // 总资产
        BigDecimal totalWorthValue = new BigDecimal(0);
        // 总当日收益
        BigDecimal totalTodayIncome = new BigDecimal(0);
        //总持仓收益
        BigDecimal totalShareIncome = new BigDecimal(0);

//        /**
//         * 交易记录
//         */
//        // 查出这个用户下所有的未确认的交易记录，传ClientId
//        Map<String, Object> map = tradeApplyQueryService.query(GlobalConstant.MAX_REQUEST_NUM, 1, 1, "1", "",
//            user.getExternalClientId(), "", "", "", GlobalConstant.TACONFIRM_FLAG_UNCONFIRM, "", "", "", "", "",
//            "", "", "");
//
//        // 查询结果
//        List<Map<String, Object>> list = new ArrayList<>();
//        HundsunUtils.ConvertToList(map, list, result);
//        if (!result.getSuccess()) {
//            return result;
//        }
//        // populate applys
//        ApplyListResult applyListResult = new ApplyListResult();
//        List<ApplyModel> applys = ModelPopulateUtils.populateApply(list, applyListResult, null, null);
//        // 把T0基金过滤掉，因为T0基金有专门的页面来显示
//        queryService.filterT0(applys, true);
        // 获取T+0基金
        List<Lookup> lookups = lookupDao.getLookupByType(RuleConstant.RULE_LOOKUP_TYPE_T0FUND);


        List<Profit> profitList = profitService.getUserNewProfit(userId.intValue(), user.getExternalClientId());
        List<FundDividents> fundDividents = fundDividentsDao.selectDividend(userId.intValue(), user.getExternalClientId(), null, null);
        List<ShareModel> normalShares = new ArrayList<>();
        for (Profit profit : profitList) {
            if (profit.getTradeAcco().startsWith("ZH") || CalculateAssetsUtils.isT0Fund(lookups, profit.getFundCode())) {
                continue;
            }
            ShareModel shareModel = new ShareModel();
            shareModel.setFundCode(profit.getFundCode());
            UserBank userBank = userBankDao.getByTradeAccount(profit.getTradeAcco());
            if (userBank != null) {
                shareModel.setBranchBank(userBank.getBranchbank());
                shareModel.setBranchBankName(userBank.getBankBranchName());
                shareModel.setBankCode(userBank.getBankCode());
                shareModel.setBankName(userBank.getBankName());
            }

            shareModel.setTradeAccount(profit.getTradeAcco());
            shareModel.setNetValue(profit.getNetValue());
            FundNetValueResult fundNetValue = fundDetailService.getFundNetValue(profit.getFundCode(), DateUtils.stringToDateWithTime(profit.getCreateTime()));
            shareModel.setFundName(fundNetValue.getChiNameAbbr());
            shareModel.setNetValueDate(fundNetValue.getTradingDay());
            netValueDate = fundNetValue.getTradingDay();
            // 设置前端显示的基金类型
            shareModel.setAppFundType(fundNetValue.getFundTypeCode());
            shareModel.setDailyProfit(fundNetValue.getDailyProfit());
            shareModel.setTodayIncomeRate(fundNetValue.getNvDailyGrowthRate());
            shareModel.setCurrentShare(profit.getShares());
            BigDecimal todayIncome = profit.getProfitValue();
            BigDecimal totalDividend = new BigDecimal(0);
            for (FundDividents dividendModel : fundDividents) {
                if ("1".equals(dividendModel.getAutoBuy()) && dividendModel.getTradeAcco().equals(shareModel.getTradeAccount()) && dividendModel.getFundCode().equals(shareModel.getFundCode())) {
                    if (dividendModel.getDividendDate().equals(DateUtils.formatDate4(DateUtils.addDay(new Date(), -1)))) {
                        todayIncome = MoneyUtils.add(todayIncome, dividendModel.getDividendBala());
                    }
                    if (dividendModel.getDividendDate().compareTo(DateUtils.formatDate4(new Date())) < 0) {
                        totalDividend = MoneyUtils.add(totalDividend, dividendModel.getDividendBala());
                    }
                    if (DateUtils.formatDate4(new Date()).compareTo(dividendModel.getEquityRegDate()) >= 0 && DateUtils.formatDate4(new Date()).compareTo(dividendModel.getDividendDate()) <= 0) {
                        shareModel.setDividends("该基金最近有分红配送");
                    }
                }

            }
            if (shareModel.getDividends() == null) {
                shareModel.setDividends("");
            }

            List<CdUserShare> cdUserShares = cdUserShareDao.selectNewShare(userId.intValue(), user.getExternalClientId(), shareModel.getTradeAccount(), profit.getFundCode());
            BigDecimal unpaidIncome = new BigDecimal(0);
            if (!cdUserShares.isEmpty()) {
                //TODO: 到时候自测的时候 关注一下 这个数据  是否对应
                unpaidIncome = cdUserShares.get(0).getUnpaidIncome();
                shareModel.setEnableShares(cdUserShares.get(0).getEnableShares());
                shareModel.setShareType(cdUserShares.get(0).getShareType());
                shareModel.setAutoBuy(cdUserShares.get(0).getAutoBuy());
                shareModel.setCapitalMode(cdUserShares.get(0).getCapitalMode());
                shareModel.setBankAccount(cdUserShares.get(0).getBankAccount());
//                // 根据恒生银行编号获取银行名称
//                List<Lookup> lookupsBank = lookupDao.getLookupByType(RuleConstant.RULE_LOOKUP_TYPE_EPAYBANK);
//                if (lookupsBank != null) {
//                    for (Lookup lookup : lookupsBank) {
//                        if (lookup.getRuleValue().equals(shareModel.getBankCode())) {
//                            shareModel.setBankName(lookup.getRuleText());
//                            break;
//                        }
//                    }
//                }
            }
            BigDecimal worthValue = shareModel.getEnableShares().multiply(shareModel.getNetValue());
            worthValue = MoneyUtils.add(worthValue, unpaidIncome);
            shareModel.setWorthValue(worthValue);
            //如果是 货币基金 要减去昨日收益  因为货币基金的资产到的迟  所以要和资产同步展示  如果收益日期不是 前一天就不需要减去
            if (shareModel.getAppFundType() == GlobalConstant.CURRENCY_APP_FUND_TYPE_ONE || shareModel.getAppFundType() == GlobalConstant.CURRENCY_APP_FUND_TYPE_TWO) {
                shareModel.setTotalAccumIncome(MoneyUtils.subtract(MoneyUtils.add(profit.getAccumulateProfitValue(), totalDividend), todayIncome));
//                if (DateUtils.formatDate(DateUtils.addDay(new Date(), -1)).equals(profit.getDateTime())) {
//                    shareModel.setTotalAccumIncome(MoneyUtils.subtract(MoneyUtils.add(profit.getAccumulateProfitValue(), totalDividend), todayIncome));
//                } else {
//                    shareModel.setTotalAccumIncome(MoneyUtils.add(profit.getAccumulateProfitValue(), totalDividend));
//                }
            } else {
                shareModel.setTotalAccumIncome(MoneyUtils.add(profit.getAccumulateProfitValue(), totalDividend));
            }

            totalAccumIncome = MoneyUtils.add(shareModel.getTotalAccumIncome(), totalAccumIncome);

            TradeOrders tradeOrders = TradeOrders.builder()
                .userId(userId.intValue())
                .clientId(profit.getClientId())
                .fundCode(profit.getFundCode())
                .tradeAcco(profit.getTradeAcco())
                .taconfirmFlag(GlobalConstant.TACONFIRM_FLAG_UNCONFIRM)
                .build();
            List<TradeOrders> tradeOrdersList = tradeOrdersDao.selectSellUnConfirmTrade(tradeOrders);


            //Integer sellInTransit = CalculateAssetsUtils.numSellOfInTransit(applys, lookups, false, shareModel.getFundCode(), shareModel.getTradeAccount());
            shareModel.setSellInTransit(tradeOrdersList.size());

            shareModel.setClearDate(fundNetValue.getCarryOverDateRemark());
            totalWorthValue = totalWorthValue.add(shareModel.getWorthValue());

            totalTodayIncome = totalTodayIncome.add(todayIncome);
            todayIncome = todayIncome.setScale(2, BigDecimal.ROUND_HALF_UP);
            shareModel.setTodayIncome(todayIncome);
//            SecurityProduct product = fundDetailService.getSecurityProduct(shareModel.getFundCode());
//
//            if (product == null) {
//                log.error("Security Product is not exist");
//                result.setErrorMessage(MessageUtil.getErrorMessage(result.getErrorCode(), null));
//                result.setSuccess(false);
//                result.setErrorCode(ErrorConstant.ERROR_FUND_NOT_EXIST);
//                return result;
//            }
//
//            // 七日年化率
//            FundMMYieldPerformance perf = fundMMYieldPerformanceService.getFundMMYieldPerformance(product.getInnerCode());
//            if (perf != null && perf.getLatestWeeklyYield() != null ){
//                shareModel.setLatestWeeklyYield(MoneyUtils.formatMoney(perf.getLatestWeeklyYield(), 2));// 最近7日折算年收益率（%）
//            }else{
//                shareModel.setLatestWeeklyYield("");
//            }
            shareModel.setLatestWeeklyYield("");
//            shareModel.setCanDividend(true);
//            if (shareModel.getAppFundType() == 900000 || shareModel.getAppFundType() == 1109){
//                shareModel.setCanDividend(false);
//            }else {
//                List<FundCombinationMapping> funds = fundCombinationMappingDao.selectAll();
//                if (!funds.isEmpty()){
//                    for (FundCombinationMapping fund : funds){
//                        if (shareModel.getFundCode().equals(fund.getFundCode())){
//                            shareModel.setCanDividend(false);
//                        }
//                    }
//                }
//            }
            normalShares.add(shareModel);
        }
        BigDecimal totalInTransit = new BigDecimal(0);
        TradeOrders tradeOrders = TradeOrders.builder().userId(userId.intValue()).clientId(user.getExternalClientId()).build();
        List<TradeOrders> tradeOrdersList = tradeOrdersDao.selectBuyUnConfirmTrade(tradeOrders);
        Integer numInTransit = 0;
        //Integer numInTransit = CalculateAssetsUtils.numOfInTransitWithoutPortfolio(applys, lookups, null);
        for (TradeOrders to : tradeOrdersList) {
            if (CalculateAssetsUtils.isT0Fund(lookups, to.getFundCode())) {
                continue;
            }
            numInTransit++;
            totalInTransit = MoneyUtils.add(totalInTransit, to.getBalance());
        }
        //totalInTransit = CalculateAssetsUtils.sumOfInTransitWithoutPortfolio(applys, lookups, null);
        totalWorthValue = MoneyUtils.add(totalWorthValue, totalInTransit);

        List<ShareModel> normalSharesNew = getShareModel(normalShares, null);
        List<ShareModel> normalSharesReal = new ArrayList<>();
        for (int i = 1; i <= normalSharesNew.size(); i++) {
            if (i >= beginNum && i < requestNum + beginNum) {
                normalSharesReal.add(normalSharesNew.get(i - 1));
            }
        }
        result.setSuccess(true);
        result.setShares(normalSharesReal);
        result.setNetValueDate(netValueDate);
        result.setTotalInTransit(totalInTransit);
        result.setTotalNumInTransit(numInTransit);
        result.setTotalAccumIncome(totalAccumIncome);
        result.setTotalFundBalance(totalFundBalance);
        result.setTotalTodayIncome(totalTodayIncome);
        result.setTotalShareIncome(totalShareIncome);
        result.setTotalWorthValue(totalWorthValue);

        return result;
    }

    // 获取单个基金资产
    @Override
    public BaseResult getFundShares(Long userId, String fundCode) throws BaseException, BaseAppException {
        User user = userService.getUser(userId);
        BaseResult result = new BaseResult();
        // 判断是否已开户
        if (user == null || StringUtil.isEmpty(user.getExternalClientId())) {
            result.setErrorType(GlobalConstant.ERROR_TYPE_APPLICATION);
            result.setSuccess(false);
            result.setErrorCode(ErrorConstant.ERROR_NO_ACCOUNT);
            return result;
        }
        Date netValueDate = DateUtils.addDay(new Date(), -1); //默认净值日期为前一天
        // 获取T+0基金
        List<Lookup> lookups = lookupDao.getLookupByType(RuleConstant.RULE_LOOKUP_TYPE_T0FUND);

        List<Profit> profitList = profitDao.selectNewProfit(userId.intValue(), user.getExternalClientId(), null, fundCode);
        List<FundDividents> fundDividents = fundDividentsDao.selectDividend(userId.intValue(), user.getExternalClientId(), null, fundCode);
        FundModel fundModel = queryService.queryFund(fundCode);

        List<ShareModel> normalShares = new ArrayList<>();
        for (Profit profit : profitList) {
            if (profit.getTradeAcco().startsWith("ZH") || CalculateAssetsUtils.isT0Fund(lookups, profit.getFundCode())) {
                continue;
            }
            ShareModel shareModel = new ShareModel();
            shareModel.setFundCode(fundCode);
            UserBank userBank = userBankDao.getByTradeAccount(profit.getTradeAcco());
            if (userBank != null) {
                shareModel.setBranchBank(userBank.getBranchbank());
                shareModel.setBranchBankName(userBank.getBankBranchName());
                shareModel.setBankCode(userBank.getBankCode());
                shareModel.setBankName(userBank.getBankName());
            }
            shareModel.setFundStatus(fundModel.getFundStatus());
            shareModel.setTradeAccount(profit.getTradeAcco());
            shareModel.setNetValue(profit.getNetValue());
            FundNetValueResult fundNetValue = fundDetailService.getFundNetValue(fundCode, DateUtils.stringToDateWithTime(profit.getCreateTime()));
            shareModel.setFundName(fundNetValue.getChiNameAbbr());
            shareModel.setNetValueDate(fundNetValue.getTradingDay());
            netValueDate = fundNetValue.getTradingDay();
            // 设置前端显示的基金类型
            shareModel.setAppFundType(fundNetValue.getFundTypeCode());
            shareModel.setDailyProfit(fundNetValue.getDailyProfit());
            shareModel.setTodayIncomeRate(fundNetValue.getNvDailyGrowthRate());
            shareModel.setCurrentShare(profit.getShares());
            BigDecimal todayIncome = profit.getProfitValue();
            BigDecimal totalDividend = new BigDecimal(0);
            for (FundDividents dividendModel : fundDividents) {
                if ("1".equals(dividendModel.getAutoBuy()) && dividendModel.getTradeAcco().equals(shareModel.getTradeAccount())) {
                    if (dividendModel.getDividendDate().equals(DateUtils.formatDate4(DateUtils.addDay(new Date(), -1)))) {
                        todayIncome = MoneyUtils.add(todayIncome, dividendModel.getDividendBala());
                    }
                    if (dividendModel.getDividendDate().compareTo(DateUtils.formatDate4(new Date())) < 0) {
                        totalDividend = MoneyUtils.add(totalDividend, dividendModel.getDividendBala());
                    }
                    if (DateUtils.formatDate4(new Date()).compareTo(dividendModel.getEquityRegDate()) >= 0 && DateUtils.formatDate4(new Date()).compareTo(dividendModel.getDividendDate()) <= 0) {
                        shareModel.setDividends("该基金最近有分红配送");
                    }
                }

            }
            if (shareModel.getDividends() == null) {
                shareModel.setDividends("");
            }

            List<CdUserShare> cdUserShares = cdUserShareDao.selectNewShare(userId.intValue(), user.getExternalClientId(), shareModel.getTradeAccount(), fundCode);
            BigDecimal unpaidIncome = new BigDecimal(0);
            if (!cdUserShares.isEmpty()) {
                unpaidIncome = cdUserShares.get(0).getUnpaidIncome();
                shareModel.setEnableShares(cdUserShares.get(0).getEnableShares());
                shareModel.setShareType(cdUserShares.get(0).getShareType());
                shareModel.setCapitalMode(cdUserShares.get(0).getCapitalMode());
                shareModel.setAutoBuy(cdUserShares.get(0).getAutoBuy());
                shareModel.setBankAccount(cdUserShares.get(0).getBankAccount());
//                // 根据恒生银行编号获取银行名称
//                List<Lookup> lookupsBank = lookupDao.getLookupByType(RuleConstant.RULE_LOOKUP_TYPE_EPAYBANK);
//                if (lookupsBank != null) {
//                    for (Lookup lookup : lookupsBank) {
//                        if (lookup.getRuleValue().equals(shareModel.getBankCode())) {
//                            shareModel.setBankName(lookup.getRuleText());
//                            break;
//                        }
//                    }
//                }
            }
            BigDecimal worthValue = shareModel.getEnableShares().multiply(shareModel.getNetValue());
            worthValue = MoneyUtils.add(worthValue, unpaidIncome);
            shareModel.setWorthValue(worthValue);
            //如果是 货币基金 要减去昨日收益  因为货币基金的资产到的迟  所以要和资产同步展示  如果收益日期不是 前一天就不需要减去
            if (shareModel.getAppFundType() == GlobalConstant.CURRENCY_APP_FUND_TYPE_ONE || shareModel.getAppFundType() == GlobalConstant.CURRENCY_APP_FUND_TYPE_TWO) {
                shareModel.setTotalAccumIncome(MoneyUtils.subtract(MoneyUtils.add(profit.getAccumulateProfitValue(), totalDividend), todayIncome));
//                if (DateUtils.formatDate(DateUtils.addDay(new Date(), -1)).equals(profit.getDateTime())) {
//                    shareModel.setTotalAccumIncome(MoneyUtils.subtract(MoneyUtils.add(profit.getAccumulateProfitValue(), totalDividend), todayIncome));
//                } else {
//                    shareModel.setTotalAccumIncome(MoneyUtils.add(profit.getAccumulateProfitValue(), totalDividend));
//                }
            } else {
                shareModel.setTotalAccumIncome(MoneyUtils.add(profit.getAccumulateProfitValue(), totalDividend));
            }
            todayIncome = todayIncome.setScale(2, BigDecimal.ROUND_HALF_UP);
            shareModel.setTodayIncome(todayIncome);
//            /**
//             * 交易记录
//             */
//            // 查出这个用户下所有的未确认的交易记录，传ClientId
//            Map<String, Object> map = tradeApplyQueryService.query(GlobalConstant.MAX_REQUEST_NUM, 1, 1, "1", "",
//                user.getExternalClientId(), "", "", "", GlobalConstant.TACONFIRM_FLAG_UNCONFIRM, "", "", "", "", "",
//                "", "", "");
//
//            // 查询结果
//            List<Map<String, Object>> list = new ArrayList<>();
//            HundsunUtils.ConvertToList(map, list, result);
//            if (!result.getSuccess()) {
//                return result;
//            }
            // populate applys
            //ApplyListResult applyListResult = new ApplyListResult();
//            List<ApplyModel> applys = ModelPopulateUtils.populateApply(list, applyListResult, null, null);
//            // 把T0基金过滤掉，因为T0基金有专门的页面来显示
//            queryService.filterT0(applys, true);
            // 只有列表需要
//            Integer sellInTransit = CalculateAssetsUtils.numSellOfInTransit(applys, lookups, false, shareModel.getFundCode(), shareModel.getTradeAccount());
//            shareModel.setSellInTransit(sellInTransit);
            // 获取基金类型
            NewsModel newsModel = queryService.getRiskLevel(shareModel.getFundCode());
            if (newsModel != null) {
                shareModel.setFundType(newsModel.getFundType());
                shareModel.setRiskLevel(newsModel.getRiskLevel());
                shareModel.setRiskLevelString(newsModel.getRiskLevelString());
            }

            shareModel.setClearDate(fundNetValue.getCarryOverDateRemark());
            SecurityProduct product = fundDetailService.getSecurityProduct(shareModel.getFundCode());

            if (product == null) {
                log.error("Security Product is not exist");
                result.setErrorMessage(MessageUtil.getErrorMessage(result.getErrorCode(), null));
                result.setErrorCode(ErrorConstant.ERROR_FUND_NOT_EXIST);
                result.setSuccess(false);
                return result;
            }

            // 七日年化率
            FundMMYieldPerformance perf = fundMMYieldPerformanceService.getFundMMYieldPerformance(product.getInnerCode());
            if (perf != null && perf.getLatestWeeklyYield() != null) {
                shareModel.setLatestWeeklyYield(MoneyUtils.formatMoney(perf.getLatestWeeklyYield(), 2));// 最近7日折算年收益率（%）
            } else {
                shareModel.setLatestWeeklyYield("");
            }

            shareModel.setCanDividend(true);
            if (shareModel.getAppFundType() == GlobalConstant.CURRENCY_APP_FUND_TYPE_ONE || shareModel.getAppFundType() == GlobalConstant.CURRENCY_APP_FUND_TYPE_TWO) {
                shareModel.setCanDividend(false);
                shareModel.setDividendMethodString("当前基金仅支持红利再投资");
            } else {
                String d = DateUtils.dateToSimpleStr(DateUtils.addDay(new Date(), -12));
                List<Profit> portfolioProfits = profitDao.selectNewPortfolioProfit(userId.intValue(), user.getExternalClientId(), d);
                if (!portfolioProfits.isEmpty()) {
                    for (Profit portfolioProfit : portfolioProfits) {
                        if (shareModel.getFundCode().equals(portfolioProfit.getFundCode())) {
                            shareModel.setCanDividend(false);
                            shareModel.setDividendMethodString("您持有的组合中有该基金，根据组合交易规则，组合基金暂不支持修改分红方式");
                            break;
                        }
                    }
                }
            }
            normalShares.add(shareModel);
        }

        List<ShareModel> normalSharesNew = getShareModel(normalShares, fundCode);

        result.setSuccess(true);
        result.setResult(normalSharesNew);

        return result;
    }


    /**
     * 瑞富宝资产详情
     *
     * @param userId
     * @param fundCode
     * @return
     * @throws BaseAppException
     */
    @Override
    public WalletDetailResult getWalletDetailByFundCode(Long userId, String fundCode) throws BaseAppException {
        // 校验fundCode是否在T0列表中
        List<Lookup> lookups = lookupDao.getLookupByType(RuleConstant.RULE_LOOKUP_TYPE_T0FUND);


        SecurityProduct product = fundDetailService.getSecurityProduct(fundCode);

        WalletDetailResult result = new WalletDetailResult();
        //AssetsResult assetsResult = queryService.queryWalletAssets(userId);

        // --------------- 和用户相关内容 begin ---------------
        // 是否有余额
        boolean hasBalance = false;
        User user = userService.getUser(userId);

        //每日最高限额
        if (user != null) {
            walletService.setMaxLimit(result, lookups, fundCode, user.getIsOrg());

            //
            // 宝盈不支持机构快速赎回 // spy 2017-11-3 13:26:44
            if (FundUtil.isBaoYingT0AB(fundCode)) {
                if (user.getIsOrg()) {
                    result.setCanFastRedeem(false);
                }
            }
        }

//        /**
//         * Step 2: 交易记录查询
//         */
//        // 查出这个用户下所有的未确认的交易记录，传ClientId
//        Map<String, Object> map = tradeApplyQueryService.query(GlobalConstant.MAX_REQUEST_NUM, 1, 1, "1", "", user.getExternalClientId(), "", "", "", GlobalConstant.TACONFIRM_FLAG_UNCONFIRM, "", "", "", "", "", "", "", "");
//
//        // 查询结果
//        List<Map<String, Object>> list = new ArrayList<>();
//        HundsunUtils.ConvertToList(map, list, result);
//        if (!result.getSuccess()) {
//            return result;
//        }
//        // populate applys
//        ApplyListResult applyListResult = new ApplyListResult();
//        List<ApplyModel> applys = ModelPopulateUtils.populateApply(list, applyListResult, null, null);

        List<Profit> profitList = profitDao.selectNewProfit(userId.intValue(), user.getExternalClientId(), null, fundCode);
        //持有基金列表
        List<AssetFundModel> fundDetailList = new ArrayList<AssetFundModel>();

        for (Profit profit : profitList) {
            if (profit.getTradeAcco().startsWith("ZH") || !CalculateAssetsUtils.isT0Fund(lookups, profit.getFundCode())) {
                continue;
            }
            if (profit.getShares().compareTo(BigDecimal.valueOf(0)) == 0) {
                continue;
            }
            // 获取 净值信息
            FundNetValueResult fundNetValue = fundDetailService.getFundNetValue(fundCode, DateUtils.stringToDateWithTime(profit.getCreateTime()));
            //获取 份额详情
            List<CdUserShare> cdUserShares = cdUserShareDao.selectNewShare(userId.intValue(), user.getExternalClientId(), profit.getTradeAcco(), fundCode);

            AssetFundModel model = new AssetFundModel();
            model.setAssetType(GlobalConstant.ASSET_TYPE_WALLET);
            model.setTradeAcco(profit.getTradeAcco());
            model.setFundCode(fundCode);
            model.setCurrentShares(profit.getShares());
            if (!cdUserShares.isEmpty()) {
                model.setEnableShares(cdUserShares.get(0).getEnableShares());
                model.setUnpaidIncome(cdUserShares.get(0).getUnpaidIncome());
            }
            model.setNetValue(fundNetValue.getUnitNV());

            BigDecimal worthValue = model.getEnableShares().multiply(model.getNetValue());
            worthValue = MoneyUtils.add(worthValue, model.getUnpaidIncome());
            worthValue = worthValue.setScale(2, BigDecimal.ROUND_HALF_UP);
            //设置每个基金的资产
            model.setTotalWorthValue(worthValue);

            BigDecimal todayIncome = profit.getProfitValue();
            BigDecimal accumIncome = new BigDecimal(0);
            accumIncome = MoneyUtils.subtract(profit.getAccumulateProfitValue(), todayIncome);
            //如果收益日期不是 前一天就不需要减去 日收益  目的是和资产保持 同步
//            if (DateUtils.formatDate(DateUtils.addDay(new Date(), -1)).equals(profit.getDateTime())) {
//                accumIncome = MoneyUtils.subtract(profit.getAccumulateProfitValue(), todayIncome);
//            } else {
//                accumIncome = profit.getAccumulateProfitValue();
//            }

            model.setTotalAccumIncome(accumIncome.setScale(2, BigDecimal.ROUND_HALF_UP));

            model.setTotalTodayIncome(todayIncome.setScale(2, BigDecimal.ROUND_HALF_UP));

            if (model.getDividends() == null) {
                model.setDividends("");
            }


//            //是否在途
//            model.setInTransit(CalculateAssetsUtils.checkInTransit(applys, lookups, true, fundCode, model.getTradeAcco()));
//            //在途金额
//            BigDecimal oneInTransit = CalculateAssetsUtils.sumOfInTransit(applys, lookups, true, model.getFundCode(), model.getTradeAcco());
//            model.setInTransitAmount(oneInTransit);
//            //在途笔数
//            model.setInTransitNum(CalculateAssetsUtils.numOfInTransit(applys, lookups, true, model.getFundCode(), model.getTradeAcco()));
//            //设置每个基金的资产
//            model.setTotalWorthValue(MoneyUtils.add(worthValue, oneInTransit));
//            //赎回在途笔数
//            Integer sellInTransit = CalculateAssetsUtils.numSellOfInTransit(applys, lookups, true, model.getFundCode(), model.getTradeAcco());
//            model.setSellInTransit(sellInTransit);

            switch (model.getFundCode()) {
                case GlobalConstant.T0_FUND_JINYING_A:
                    model.setWalletString("每月15日结转当期收益");
                    break;
                case GlobalConstant.T0_FUND_JINYING_B:
                    model.setWalletString("每月15日结转当期收益");
                    break;
                case GlobalConstant.T0_FUND_CHANGCHENG_A:
                    model.setWalletString("每月15日结转当期收益");
                    break;
                case GlobalConstant.T0_FUND_CHANGCHENG_B:
                    model.setWalletString("每月15日结转当期收益");
                    break;
                case GlobalConstant.T0_FUND_BAOYING_A:
                    model.setWalletString("每月5日结转当期收益");
                    break;
                case GlobalConstant.T0_FUND_BAOYING_B:
                    model.setWalletString("每月5日结转当期收益");
                    break;
                case GlobalConstant.T0_FUND_JINYING2_A:
                    model.setWalletString("每日结转当期收益");
                    break;
                case GlobalConstant.T0_FUND_JINYING2_B:
                    model.setWalletString("每日结转当期收益");
                    break;
                case GlobalConstant.T0_FUND_CHANGCHENG_E:
                    model.setWalletString("每日结转当期收益");
                    break;
                default:
                    break;
            }


            //logger.warn("单个基金在途金额:{},单个基金资产:{}", model.getInTransitAmount(), model.getTotalWorthValue());
            fundDetailList.add(model);
        }


        //将多卡的持有份额合并   并累加份额 资产 等信息
        List<AssetFundModel> fundDetailListNew = new ArrayList<>();
        List<String> fundCodesNew = new ArrayList<>();
        for (AssetFundModel assetFundModel : fundDetailList) {
            if (fundCodesNew.contains(assetFundModel.getFundCode())) {
                for (AssetFundModel assetFundModelNew : fundDetailListNew) {
                    if (assetFundModel.getFundCode().equals(assetFundModelNew.getFundCode())) {
                        assetFundModelNew.setCost(MoneyUtils.add(assetFundModelNew.getCost(), assetFundModel.getCost()));
                        assetFundModelNew.setCurrentShares(MoneyUtils.add(assetFundModelNew.getCurrentShares(), assetFundModel.getCurrentShares()));
                        assetFundModelNew.setEnableShares(MoneyUtils.add(assetFundModelNew.getEnableShares(), assetFundModel.getEnableShares()));
                        assetFundModelNew.setInTransitAmount(MoneyUtils.add(assetFundModelNew.getInTransitAmount(), assetFundModel.getInTransitAmount()));
                        Integer sellIntransit = assetFundModelNew.getSellInTransit() + assetFundModel.getSellInTransit();
                        assetFundModelNew.setSellInTransit(sellIntransit);
                        Integer intransitNum = assetFundModelNew.getInTransitNum() + assetFundModel.getInTransitNum();
                        assetFundModelNew.setInTransitNum(intransitNum);
                        assetFundModelNew.setTotalTodayIncome(MoneyUtils.add(assetFundModelNew.getTotalTodayIncome(), assetFundModel.getTotalTodayIncome()));
                        assetFundModelNew.setTotalAccumIncome(MoneyUtils.add(assetFundModelNew.getTotalAccumIncome(), assetFundModel.getTotalAccumIncome()));
                        assetFundModelNew.setTotalWorthValue(MoneyUtils.add(assetFundModelNew.getTotalWorthValue(), assetFundModel.getTotalWorthValue()));
                    }
                }
            } else {
                fundDetailListNew.add(assetFundModel);
                fundCodesNew.add(assetFundModel.getFundCode());
            }
        }
        FundModel fundModel = queryService.queryFund(fundCode);
        for (AssetFundModel model : fundDetailListNew) {
            if (fundCode.equals(model.getFundCode())) {
                result.setTodayIncome(MoneyUtils.formatMoney(model.getTotalTodayIncome()));
                result.setWalletMoney(MoneyUtils.formatMoney(model.getTotalWorthValue()));
                result.setTotalIncome(MoneyUtils.formatMoney(model.getTotalAccumIncome()));
                result.setFundName(model.getFundName());
                result.setFundCode(model.getFundCode());
                if (fundModel != null) {
                    // 零钱;日收益;是否能提现;是否能存入
                    result.setCanBuy(fundModel.getCanBuy());
                    if (model.getEnableShares().compareTo(new BigDecimal(0)) > 0) {
                        result.setCanSell(true);
                    } else {
                        result.setCanSell(false);
                    }
                } else {
                    // 如果未找到该只基金，则不能买不能卖
                    result.setCanBuy(false);
                    result.setCanSell(false);
                }
            }

        }

        product = fundDetailService.getSecurityProduct(fundCode);

        if (product == null) {
            log.error("Security Product is not exist");
            result.setErrorCode(ErrorConstant.ERROR_FUND_NOT_EXIST);
            result.setErrorMessage(MessageUtil.getErrorMessage(result.getErrorCode(), null));
            result.setSuccess(false);
            return result;
        }
        result.setFundName(product.getChiNameAbbr());
        result.setFundCode(fundCode);
        // 七日年化率
        FundMMYieldPerformance perf = fundMMYieldPerformanceService.getFundMMYieldPerformance(product.getInnerCode());
        result.setNetValueDate(perf.getTradingDay());
        result.setLatestWeeklyYield(MoneyUtils.formatMoneyNoRound(perf.getLatestWeeklyYield(), 2));// 最近7日折算年收益率（%）
        result.setDailyProfit(MoneyUtils.formatMoney(perf.getDailyProfit(), 4));

        // 最近七天的七日年化收益率(降序)
        walletService.setWeekYield(product, result);

        result.setSuccess(true);
        return result;
    }

    @Override
    public WalletDetailResultV2 getWalletList(Long userId) throws BaseAppException {
        // 校验fundCode是否在T0列表中
        List<Lookup> lookups = lookupDao.getLookupByType(RuleConstant.RULE_LOOKUP_TYPE_T0FUND);


        WalletDetailResultV2 result = new WalletDetailResultV2();

        User user = userService.getUser(userId);

        BigDecimal totalWorthValue = null;
        BigDecimal totalTodayIncome = null;
        BigDecimal totalAccumIncome = null;

        /**
         *  交易记录查询
         */
        // 查出这个用户下所有的未确认的交易记录，传ClientId
        //Map<String, Object> map = tradeApplyQueryService.query(GlobalConstant.MAX_REQUEST_NUM, 1, 1, "1", "", user.getExternalClientId(), "", "", "", GlobalConstant.TACONFIRM_FLAG_UNCONFIRM, "", "", "", "", "", "", "", "");

        // 查询结果
        //List<Map<String, Object>> list = new ArrayList<>();
        //HundsunUtils.ConvertToList(map, list, result);
        //if (!result.getSuccess()) {
        //    return result;
        //}
        // populate applys
        //ApplyListResult applyListResult = new ApplyListResult();
        //List<ApplyModel> applys = ModelPopulateUtils.populateApply(list, applyListResult, null, null);

        List<Profit> profitList = profitService.getUserNewProfit(userId.intValue(), user.getExternalClientId());
        //持有基金列表
        List<AssetFundModel> fundDetailList = new ArrayList<AssetFundModel>();

        Date netValueDate = null;

        for (Profit profit : profitList) {
            if (profit.getTradeAcco().startsWith("ZH") || !CalculateAssetsUtils.isT0Fund(lookups, profit.getFundCode())) {
                continue;
            }
            if (profit.getShares().compareTo(BigDecimal.valueOf(0)) == 0) {
                continue;
            }
            // 获取 净值信息
            FundNetValueResult fundNetValue = fundDetailService.getFundNetValue(profit.getFundCode(), DateUtils.stringToDateWithTime(profit.getCreateTime()));
            //获取 份额详情
            List<CdUserShare> cdUserShares = cdUserShareDao.selectNewShare(userId.intValue(), user.getExternalClientId(), profit.getTradeAcco(), profit.getFundCode());
            AssetFundModel model = new AssetFundModel();
            model.setAssetType(GlobalConstant.ASSET_TYPE_WALLET);
            model.setTradeAcco(profit.getTradeAcco());
            model.setFundCode(profit.getFundCode());
            for (Lookup lookup : lookups) {
                if (lookup.getRuleValue().equals(profit.getFundCode())) {
                    model.setFundName(lookup.getRuleText());
                    break;
                }
            }
            model.setCurrentShares(profit.getShares());
            if (!cdUserShares.isEmpty()) {
                model.setEnableShares(cdUserShares.get(0).getEnableShares());
                model.setUnpaidIncome(cdUserShares.get(0).getUnpaidIncome());
            }
            model.setNetValue(fundNetValue.getUnitNV());
            model.setNetValueDate(fundNetValue.getTradingDay());
            netValueDate = fundNetValue.getTradingDay();
            BigDecimal worthValue = model.getEnableShares().multiply(model.getNetValue());
            worthValue = MoneyUtils.add(worthValue, model.getUnpaidIncome());
            totalWorthValue = MoneyUtils.add(totalWorthValue, worthValue);
            worthValue = worthValue.setScale(2, BigDecimal.ROUND_HALF_UP);
            //设置每个基金的资产
            model.setTotalWorthValue(worthValue);

            BigDecimal todayIncome = profit.getProfitValue();
            totalTodayIncome = MoneyUtils.add(totalTodayIncome, todayIncome);
            BigDecimal accumIncome = new BigDecimal(0);
            accumIncome = MoneyUtils.subtract(profit.getAccumulateProfitValue(), todayIncome);
            //如果收益日期不是 前一天就不需要减去 日收益  目的是和资产保持 同步
//            if (DateUtils.formatDate(DateUtils.addDay(new Date(), -1)).equals(profit.getDateTime())) {
//                accumIncome = MoneyUtils.subtract(profit.getAccumulateProfitValue(), todayIncome);
//            } else {
//                accumIncome = profit.getAccumulateProfitValue();
//            }

            totalAccumIncome = MoneyUtils.add(totalAccumIncome, accumIncome);
            model.setTotalAccumIncome(accumIncome.setScale(2, BigDecimal.ROUND_HALF_UP));

            model.setTotalTodayIncome(todayIncome.setScale(2, BigDecimal.ROUND_HALF_UP));

            if (model.getDividends() == null) {
                model.setDividends("");
            }

            switch (model.getFundCode()) {
                case GlobalConstant.T0_FUND_JINYING_A:
                    model.setWalletString("每月15日结转当期收益");
                    break;
                case GlobalConstant.T0_FUND_JINYING_B:
                    model.setWalletString("每月15日结转当期收益");
                    break;
                case GlobalConstant.T0_FUND_CHANGCHENG_A:
                    model.setWalletString("每月15日结转当期收益");
                    break;
                case GlobalConstant.T0_FUND_CHANGCHENG_B:
                    model.setWalletString("每月15日结转当期收益");
                    break;
                case GlobalConstant.T0_FUND_BAOYING_A:
                    model.setWalletString("每月5日结转当期收益");
                    break;
                case GlobalConstant.T0_FUND_BAOYING_B:
                    model.setWalletString("每月5日结转当期收益");
                    break;
                case GlobalConstant.T0_FUND_JINYING2_A:
                    model.setWalletString("每日结转当期收益");
                    break;
                case GlobalConstant.T0_FUND_JINYING2_B:
                    model.setWalletString("每日结转当期收益");
                    break;
                case GlobalConstant.T0_FUND_CHANGCHENG_E:
                    model.setWalletString("每日结转当期收益");
                    break;
                default:
                    break;
            }

            //logger.warn("单个基金在途金额:{},单个基金资产:{}", model.getInTransitAmount(), model.getTotalWorthValue());
            fundDetailList.add(model);
        }

        //将多卡的持有份额合并   并累加份额 资产 等信息
        List<AssetFundModel> fundDetailListNew = new ArrayList<>();
        List<String> fundCodesNew = new ArrayList<>();
        for (AssetFundModel assetFundModel : fundDetailList) {
            if (fundCodesNew.contains(assetFundModel.getFundCode())) {
                for (AssetFundModel assetFundModelNew : fundDetailListNew) {
                    if (assetFundModel.getFundCode().equals(assetFundModelNew.getFundCode())) {
                        assetFundModelNew.setAssetType(assetFundModel.getAssetType());
                        assetFundModelNew.setTradeAcco(assetFundModel.getTradeAcco());
                        assetFundModelNew.setCost(MoneyUtils.add(assetFundModelNew.getCost(), assetFundModel.getCost()));
                        assetFundModelNew.setEnableShares(MoneyUtils.add(assetFundModelNew.getEnableShares(), assetFundModel.getEnableShares()));
                        assetFundModelNew.setCurrentShares(MoneyUtils.add(assetFundModelNew.getCurrentShares(), assetFundModel.getCurrentShares()));
                        assetFundModelNew.setInTransitAmount(MoneyUtils.add(assetFundModelNew.getInTransitAmount(), assetFundModel.getInTransitAmount()));
                        Integer sellIntransit = assetFundModelNew.getSellInTransit() + assetFundModel.getSellInTransit();
                        assetFundModelNew.setSellInTransit(sellIntransit);
                        Integer intransitNum = assetFundModelNew.getInTransitNum() + assetFundModel.getInTransitNum();
                        assetFundModelNew.setInTransitNum(intransitNum);
                        assetFundModelNew.setTotalTodayIncome(MoneyUtils.add(assetFundModelNew.getTotalTodayIncome(), assetFundModel.getTotalTodayIncome()));
                        assetFundModelNew.setTotalAccumIncome(MoneyUtils.add(assetFundModelNew.getTotalAccumIncome(), assetFundModel.getTotalAccumIncome()));
                        assetFundModelNew.setTotalWorthValue(MoneyUtils.add(assetFundModelNew.getTotalWorthValue(), assetFundModel.getTotalWorthValue()));
                    }
                }
            } else {
                fundDetailListNew.add(assetFundModel);
                fundCodesNew.add(assetFundModel.getFundCode());
            }
        }
        BigDecimal totalInTransit = new BigDecimal(0);
        TradeOrders tradeOrders = TradeOrders.builder().userId(userId.intValue()).clientId(user.getExternalClientId()).build();
        List<TradeOrders> tradeOrdersList = tradeOrdersDao.selectBuyUnConfirmTrade(tradeOrders);
        Integer numInTransit = 0;
        //Integer numInTransit = CalculateAssetsUtils.numOfInTransitWithoutPortfolio(applys, lookups, null);
        for (TradeOrders to : tradeOrdersList) {
            if (!CalculateAssetsUtils.isT0Fund(lookups, to.getFundCode())) {
                continue;
            }
            numInTransit++;
            totalInTransit = MoneyUtils.add(totalInTransit, to.getBalance());
        }
        result.setInTransitAmount(totalInTransit);
        result.setInTransitNum(numInTransit);

        // 在途金额
        //result.setInTransitAmount(CalculateAssetsUtils.sumOfInTransit(applys, lookups, true, null, null));
        //在途笔数
        //result.setInTransitNum(CalculateAssetsUtils.numOfInTransit(applys, lookups, true, null, null));

        //总资产
        result.setTwv(MoneyUtils.add(totalWorthValue, result.getInTransitAmount()));
        result.setTotalWorthValue(MoneyUtils.formatMoney(MoneyUtils.add(totalWorthValue, result.getInTransitAmount()), 2));
        result.setTti(totalTodayIncome);
        result.setTotalTodayIncome(MoneyUtils.formatMoney(totalTodayIncome, 2));
        result.setTi(totalAccumIncome);
        result.setTotalIncome(MoneyUtils.formatMoney(totalAccumIncome, 2));

        result.setNetValueDate(netValueDate);

        result.setFundModelList(fundDetailListNew);

        result.setSuccess(true);
        return result;
    }

    @Override
    public CashChangeListResult getWalletCashChangeDetails(Long userId, String fundCode) {
        // T0 Funds 基金
        List<Lookup> lookups = lookupService.getLookups(RuleConstant.RULE_LOOKUP_TYPE_T0FUND);
        CashChangeListResult cashChangeListResult = new CashChangeListResult();
        List<CashChangeResult> cashChangeResults = new ArrayList<>();
        Map<String, TradeLimitModel> tradeLimitModels = new HashMap<>();

        Preconditions.checkNotNull(lookups, "T0数据为空请检查");

        User user = userService.getUser(userId);

        String custType = GlobalConstant.CUST_TYPE_ORGANIZATION;

        //List<Lookup> epayLookups = lookupDao.getLookupByType(RuleConstant.RULE_LOOKUP_TYPE_EPAYBANK);

        String brandsType = FundUtil.getT0FundBrandsType(fundCode);

        for (Lookup lookup : lookups) {
            if (EqualsUtil.equals(lookup.getRuleValue(), fundCode.trim())) {
                List<Profit> profitList = profitDao.selectNewProfit(userId.intValue(), user.getExternalClientId(), null, fundCode);
                for (Profit profit : profitList) {
                    if (profit.getShares().compareTo(BigDecimal.valueOf(0)) == 0) {
                        continue;
                    }
                    CashChangeResult cashChangeResult = new CashChangeResult();
                    UserBank userBank = userBankDao.getByTradeAccount(profit.getTradeAcco());
                    if (userBank != null) {
                        cashChangeResult.setBranchBank(userBank.getBranchbank() == null ? "" : userBank.getBranchbank());
                        cashChangeResult.setBranchBankName(userBank.getBankBranchName() == null ? "" : userBank.getBankBranchName());
                        cashChangeResult.setBankCode(userBank.getBankCode());
                        cashChangeResult.setBankName(userBank.getBankName());
                        cashChangeResult.setBankAccount(userBank.getUserBankNo());
                        cashChangeResult.setTradeAccount(profit.getTradeAcco());
                        cashChangeResult.setCapitalMode(userBank.getCapitalMode());
                    }
                    List<CdUserShare> cdUserShares = cdUserShareDao.selectNewShare(userId.intValue(), user.getExternalClientId(), cashChangeResult.getTradeAccount(), fundCode);
                    if (!cdUserShares.isEmpty()) {
                        cashChangeResult.setEnableShare(cdUserShares.get(0).getEnableShares());
                        cashChangeResult.setShareType(cdUserShares.get(0).getShareType());
                    }
                    cashChangeResult.setFundCode(lookup.getRuleValue());
//                    for (Lookup epayLookup : epayLookups) {
//                        if (cashChangeResult.getBankName().equals(epayLookup.getRuleText())) {
//                            cashChangeResult.setBankCode(epayLookup.getRuleValue());
//                        }
//                    }

                    TradeLimitModel tradeLimitModel = null;

                    /**
                     * 赎回限额
                     */
                    String fastSellKey = lookup.getRuleValue() + cashChangeResult.getShareType() + cashChangeResult.getCapitalMode()
                        + GlobalConstant.FUND_BUSIN_CODE_APPLY_SELL;
                    if (tradeLimitModels.get(fastSellKey) == null) {
                        tradeLimitModel = queryService.getTradeLimit(lookup.getRuleValue(),
                            GlobalConstant.FUND_BUSIN_CODE_APPLY_SELL, cashChangeResult.getShareType(),
                            custType,
                            cashChangeResult.getCapitalMode());

                        tradeLimitModels.put(fastSellKey, tradeLimitModel);
                    } else {
                        tradeLimitModel = tradeLimitModels.get(fastSellKey);
                    }

                    if (tradeLimitModel != null) {
                        cashChangeResult.setMinHoldShares(tradeLimitModel.getMinHoldShares());
                        cashChangeResult.setMaxValueForSell(tradeLimitModel.getMaxValue());
                        cashChangeResult.setMinValue(tradeLimitModel.getMinValue());
                    } else {
                        // 如果未找到，则不返回，前端根据是否有返回来决定是否做验证限制
                        log.warn("sell tradeLimitModel does not exist");
                    }

                    // 设置最高可快速赎回的金额
                    // 如果为空，则不返回，前端根据是否有返回来决定是否做验证限制
                    if (!StringUtil.isEmpty(lookup.getComponentValue())) {
                        String str = lookup.getComponentValue();

                        String maxLimit = LookupUtil.getT0FieldValueStr(str, user.getIsOrg(), RuleConstant.FIELD_DAY_LIMIT);

                        // 如果转换出错，则默认为最大值，让交易成功提交，由直销系统做最后的限制
                        cashChangeResult.setMaxValueForFastSell(BigDecimalUtil
                            .ConvertToBigDecimal(maxLimit, new BigDecimal(Integer.MAX_VALUE)));
                    }


                    //TODO 这里结构设计有问题,先保持原先结构  spy 2017-11-1


                    String str = lookup.getComponentValue();
                    if (FundUtil.isBaoYingT0AB(fundCode)) {
                        Lookup tmpLookup = lookupService.getLookup(RuleConstant.T0FUND_BAOYING_CONFIG);
                        str = tmpLookup.getComponentValue();
                    }

                    if (StringUtil.isNotEmpty(str) && LookupUtil.isJSONObject(str)) {

                        String dayDealLimitStr = LookupUtil.getT0FieldValueStr(str, user.getIsOrg(), RuleConstant.FIELD_DAY_LIMIT);
                        String singleDealLimitStr = LookupUtil.getT0FieldValueStr(str, user.getIsOrg(), RuleConstant.FIELD_SINGLE_DEAL_LIMIT);
                        String totalCountStr = LookupUtil.getT0FieldValueStr(str, user.getIsOrg(), RuleConstant.FIELD_DAY_DEAL_COUNT_LIMIT);

                        // 单日交易限制
                        BigDecimal dayDealMaxValue = BigDecimalUtil.ConvertToBigDecimal(dayDealLimitStr);
                        cashChangeResult.setFastRedeemDayDealMaxValue(BigDecimalUtil.ConvertToBigDecimal(dayDealLimitStr));

                        // 剩余单日额度 spy 2017-11-3 10:56:05
                        if (EqualsUtil.equals("-1", dayDealLimitStr)) {
                        } else {
                            BigDecimal usedMoney = walletService.getFastRedeemDayUsedMoney(userId, brandsType);
                            BigDecimal finalValue = MoneyUtils.max(dayDealMaxValue.subtract(usedMoney), BigDecimal.ZERO);
                            cashChangeResult.setFastRedeemRetainDayDealMaxValue(finalValue);
                        }

                        // 单笔交易限额
                        cashChangeResult.setFastRedeemSingleDealMaxValue(BigDecimalUtil.ConvertToBigDecimal(singleDealLimitStr));

                        // 可交易总次数
                        int totalCount = Integer.valueOf(totalCountStr);
                        cashChangeResult.setFastRedeemTotalCountPerDay(Integer.valueOf(totalCountStr));

                        // 可交易剩余次数(总次数-已用次数)
                        if (EqualsUtil.equals("-1", totalCountStr)) {
                        } else {
                            int count = Math.max(totalCount - walletService.getFastRedeemCountInCurrentDay(userId, brandsType), 0);
                            cashChangeResult.setFastRedeemRetainCountPerDay(count);
                        }
                        switch (cashChangeResult.getFundCode()) {
                            case GlobalConstant.T0_FUND_JINYING_A:
                                cashChangeResult.setFastRedeemTime("");
                                cashChangeResult.setWalletString("未结转收益于每月15日结转，结转后可赎回");
                                break;
                            case GlobalConstant.T0_FUND_JINYING_B:
                                cashChangeResult.setFastRedeemTime("");
                                cashChangeResult.setWalletString("未结转收益于每月15日结转，结转后可赎回");
                                break;
                            case GlobalConstant.T0_FUND_CHANGCHENG_A:
                                cashChangeResult.setFastRedeemTime("快速取现时间为：每个工作日9:00-16:45");
                                cashChangeResult.setWalletString("未结转收益于每月15日结转，结转后可赎回");
                                break;
                            case GlobalConstant.T0_FUND_CHANGCHENG_B:
                                cashChangeResult.setFastRedeemTime("");
                                cashChangeResult.setWalletString("未结转收益于每月15日结转，结转后可赎回");
                                break;
                            case GlobalConstant.T0_FUND_BAOYING_A:
                                cashChangeResult.setFastRedeemTime("");
                                cashChangeResult.setWalletString("未结转收益于每月5日结转，结转后可赎回");
                                break;
                            case GlobalConstant.T0_FUND_BAOYING_B:
                                cashChangeResult.setFastRedeemTime("");
                                cashChangeResult.setWalletString("未结转收益于每月5日结转，结转后可赎回");
                                break;
                            case GlobalConstant.T0_FUND_JINYING2_A:
                                cashChangeResult.setFastRedeemTime("");
                                cashChangeResult.setWalletString("每日结转当期收益");
                                break;
                            case GlobalConstant.T0_FUND_CHANGCHENG_E:
                                cashChangeResult.setFastRedeemTime("快速取现时间为：每个工作日9:00-16:45");
                                cashChangeResult.setWalletString("每日结转当期收益");
                                break;
                            case GlobalConstant.T0_FUND_JINYING2_B:
                                cashChangeResult.setFastRedeemTime("");
                                cashChangeResult.setWalletString("每日结转当期收益");
                                break;

                            default:
                                break;
                        }
                    }
                    cashChangeResults.add(cashChangeResult);
                }
                cashChangeListResult.setCashChangeResults(cashChangeResults);
            }
        }
        return cashChangeListResult;
    }


    @Override
    public List<ShareModel> getShareModel(List<ShareModel> normalShares, String fundCode) {
        //将多卡的持有份额合并   并累加份额 资产 等信息
        List<ShareModel> normalSharesNew = new ArrayList<>();
        List<String> fundCodesNew = new ArrayList<>();
        for (ShareModel shareModel : normalShares) {
            if (fundCodesNew.contains(shareModel.getFundCode())) {
                for (ShareModel shareModelNew : normalSharesNew) {
                    if (shareModel.getFundCode().equals(shareModelNew.getFundCode())) {
                        shareModelNew.setAvailableDueShare(MoneyUtils.add(shareModelNew.getAvailableDueShare(), shareModel.getAvailableDueShare()));
                        shareModelNew.setCurrentShare(MoneyUtils.add(shareModelNew.getCurrentShare(), shareModel.getCurrentShare()));
                        shareModelNew.setEnableShares(MoneyUtils.add(shareModelNew.getEnableShares(), shareModel.getEnableShares()));
                        shareModelNew.setCost(MoneyUtils.add(shareModelNew.getCost(), shareModel.getCost()));
                        shareModelNew.setFrozenShare(MoneyUtils.add(shareModelNew.getFrozenShare(), shareModel.getFrozenShare()));
                        Integer sellIntransit = shareModelNew.getSellInTransit() + shareModel.getSellInTransit();
                        shareModelNew.setSellInTransit(sellIntransit);
                        shareModelNew.setTodayIncome(MoneyUtils.add(shareModelNew.getTodayIncome(), shareModel.getTodayIncome()));
                        shareModelNew.setTotalAccumIncome(MoneyUtils.add(shareModelNew.getTotalAccumIncome(), shareModel.getTotalAccumIncome()));
                        shareModelNew.setWorthValue(MoneyUtils.add(shareModelNew.getWorthValue(), shareModel.getWorthValue()));

                        shareModelNew.getShareDetails().add(shareModel);
                    }
                }
            } else {
                if (fundCode != null) {
                    if (StringUtils.isNotBlank(fundCode)) {
                        if (!fundCode.equals(shareModel.getFundCode())) {
                            continue;
                        }
                    }
                }
                List<ShareModel> sharesInside = new ArrayList<>();
                //因为 如果用原来的模型会导致无限循环  所以要新new一个
                ShareModel shareModelCopy = new ShareModel();
                BeanUtils.copyProperties(shareModel, shareModelCopy);
                shareModelCopy.setShareDetails(sharesInside);
                shareModelCopy.getShareDetails().add(shareModel);
                normalSharesNew.add(shareModelCopy);
                fundCodesNew.add(shareModel.getFundCode());
            }
        }
        return normalSharesNew;
    }

    /**
     * 查询单支组合具体基金信息
     *
     * @param userId
     * @param portfolioCode
     * @return
     */
    @Override
    public PortfolioModel queryPortfolioFunds(Long userId, String portfolioCode) {
        PortfolioModel result = new PortfolioModel();
        try {
            List<Lookup> lookups = lookupDao.getLookupByType(RuleConstant.RULE_LOOKUP_TYPE_T0FUND);
            User user = userDao.getEntity(userId);
            // 判断是否已开户
            if (!BaseResultUtil.isOpen(result, user).getSuccess()) {
                return result;
            }
            String tradeAccount = "";
            List<PortfolioTradeAcco> portfolioTradeAccounts = portfolioTradeAccoDao.selectPortfolioTradeAccoByUserId(userId);
            for (PortfolioTradeAcco portfolioProfits : portfolioTradeAccounts) {
                if (portfolioProfits.getPortfolioCode().equals(portfolioCode)) {
                    tradeAccount = portfolioProfits.getPortfolioTradeAcco();
                }
            }
            //查出所有 收益 放入map 为了速度优化   然后为了防止货币基金收益迟到的问题  所以只能倒序再过滤
            List<Profit> portfolioProfits = profitDao.selectNewPortfolioProfit(userId.intValue(), user.getExternalClientId(), getOldDate());
            Map<String, Profit> profitMap = new HashMap<>();
            for (Profit profit : portfolioProfits) {
                if (profitMap.get(profit.getTradeAcco() + profit.getFundCode()) != null) {
                    continue;
                }
                profitMap.put(profit.getTradeAcco() + profit.getFundCode(), profit);
            }
            Map<String, List<Profit>> map = new HashMap<>();
            for (String p : profitMap.keySet()) {
                Profit profit = profitMap.get(p);
                if (map.get(profit.getTradeAcco()) != null) {
                    List<Profit> profits = map.get(profit.getTradeAcco());
                    profits.add(profit);
                    map.put(profit.getTradeAcco(), profits);
                } else {
                    List<Profit> profits = new ArrayList<>();
                    profits.add(profit);
                    map.put(profit.getTradeAcco(), profits);
                }
            }
            List<CdUserShare> portfolioShare = cdUserShareDao.selectNewPortfolioShare(userId.intValue(), user.getExternalClientId());
            Map<String, CdUserShare> shareMap = new HashMap<>();
            for (CdUserShare share : portfolioShare) {
                if (shareMap.get(share.getTradeAcco() + share.getFundCode()) != null) {
                    continue;
                }
                shareMap.put(share.getTradeAcco() + share.getFundCode(), share);
            }
            // 设置组合模型主要信息
            setPortfolioMainInfo(userId, portfolioCode, result, lookups, user, map, shareMap, tradeAccount);
            // 设置可以赎回
            for (AssetFundModel assetFundModel : result.getPortfolioFunds()) {
                FundModel fundModel = queryService.queryFund(assetFundModel.getFundCode());
                if (!fundModel.getCanSell()) {
                    result.setCanSell(false);
                    break;
                }
            }
            // 设值组合模型次要信息
            setPortfolioOthersInfo(userId, result);
            // 按交易账号将份额和资产进行区分
            result = extractPortfolioByTrade(result, lookups);

        } catch (BaseException baseException) {
            throw baseException;
        } catch (Exception exception) {
            ExceptionUtil.logError(log, "queryAssets - Exception:", exception);
            throw new SystemDBException("queryAssets Failure!", exception);
        }
        return result;
    }

    private void setPortfolioOthersInfo(Long userId, PortfolioModel result) {
        // 验证组合是否存在
        List<PortfolioQryModel> fundList = fundCombinationService.queryPorfolio(result.getPortfolioCode());
        String protocolName = "";
        if (fundList != null) {
            PortfolioQryModel model = fundList.get(0);
            if (model != null) {
                protocolName = model.getProtocolName();
            }
        }
        // 设置组合名称
        result.setProtocolName(protocolName);
        // 统计调仓数据 设置是否可以进行调仓
        queryService.stocks(result, fundList, userId);
    }

    private void setPortfolioMainInfo(Long userId, String portfolioCode, PortfolioModel result, List<Lookup> lookups, User user, Map<String, List<Profit>> map, Map<String, CdUserShare> shareMap, String tradeAccount) {
        // 设置组合编码
        result.setPortfolioCode(portfolioCode);
        // 组合交易账号
        //PortfolioTradeAcco portfolioTradeAcco = portfolioTradeAccoDao.selectByUserIdAndPortfolioCode(userId, portfolioCode);
        // 设置组合交易账号
        result.setTradeAcco(tradeAccount);
        // 用户组合的收益信息
        List<Profit> profits = map.get(tradeAccount);
        // 组合中包含的基金
        List<AssetFundModel> portfolioFunds = new ArrayList<>();
        // 组合累积收益
        BigDecimal portfolioAccumIncome = new BigDecimal(0);
        // 组合当日收益
        BigDecimal portfolioTodayIncome = new BigDecimal(0);
        // 组合的总资产
        BigDecimal totalWorthValue = new BigDecimal(0);
        // 累积分红
        BigDecimal totalDividend = new BigDecimal(0);
        for (Profit profit : profits) {
            portfolioAccumIncome = MoneyUtils.add(portfolioAccumIncome, profit.getAccumulateProfitValue());
            portfolioTodayIncome = MoneyUtils.add(portfolioTodayIncome, profit.getProfitValue());
            FundNetValueResult fundNetValue = fundDetailService.getFundNetValue(profit.getFundCode(), DateUtils.stringToDateWithTime(profit.getCreateTime()));
            CdUserShare cdUserShare = shareMap.get(profit.getTradeAcco() + profit.getFundCode());
            //List<CdUserShare> cdUserShares = cdUserShareDao.selectNewShare(user.getUserId().intValue(), user.getExternalClientId(), profit.getTradeAcco(), profit.getFundCode());
//            CdUserShare cdUserShare = null;
//            if (ListUtil.isNotEmpty(cdUserShares)) {
//                cdUserShare = cdUserShares.get(0);
//            }
            if (cdUserShare == null) {
                throw new BaseException("本地资产信息数据不存在,fundCode:" + profit.getFundCode());
            }
            // 用户组合分红
            List<FundDividents> fundDividents = fundDividentsDao.selectDividend(userId.intValue(), user.getExternalClientId(), tradeAccount, profit.getFundCode());
            for (FundDividents dividendModel : fundDividents) {
                if ("1".equals(dividendModel.getAutoBuy()) && dividendModel.getTradeAcco().equals(profit.getTradeAcco())) {
                    if (dividendModel.getDividendDate().equals(DateUtils.formatDate4(DateUtils.addDay(new Date(), -1)))) {
                        portfolioTodayIncome = MoneyUtils.add(portfolioTodayIncome, dividendModel.getDividendBala());
                    }
                    if (dividendModel.getDividendDate().compareTo(DateUtils.formatDate4(new Date())) < 0) {
                        totalDividend = MoneyUtils.add(totalDividend, dividendModel.getDividendBala());
                    }
                }

            }
            AssetFundModel assetFundModel = new AssetFundModel();
            // 设置基金资产模型
            setAssetFundModel(result, lookups, profit, fundNetValue, cdUserShare, assetFundModel);
            // 单支基金总资产
            BigDecimal worthValue = cdUserShare.getEnableShares().multiply(profit.getNetValue());
            worthValue = worthValue.setScale(2, BigDecimal.ROUND_HALF_UP);
            assetFundModel.setTotalWorthValue(worthValue);
            // 计算组合的总资产，用于计算组合内基金比例
            totalWorthValue = MoneyUtils.add(totalWorthValue, worthValue);


            portfolioFunds.add(assetFundModel);
        }
        // 该支组合当日收益
        portfolioTodayIncome = portfolioTodayIncome.setScale(2, BigDecimal.ROUND_HALF_UP);
        // 在循环中直接加入现金分红
        result.setPortfolioTodayIncome(portfolioTodayIncome);
        // 该支组合累积收益  总收益 + 现金分红
        result.setPortfolioAccumIncome(MoneyUtils.add(portfolioAccumIncome, totalDividend));
        // 组合总资产 = 总资产
        result.setPortfolioWorthValue(totalWorthValue);
        // 组合基金详情
        result.setPortfolioFunds(portfolioFunds);
        for (AssetFundModel assetFundModel : portfolioFunds) {
            BigDecimal rate = assetFundModel.getTotalWorthValue().divide(totalWorthValue, 4, ROUND_HALF_DOWN);
            assetFundModel.setInvestRate(rate);
        }
    }

    private void setAssetFundModel(PortfolioModel result, List<Lookup> lookups, Profit profit, FundNetValueResult fundNetValue, CdUserShare cdUserShare, AssetFundModel assetFundModel) {
        // 交易账号
        assetFundModel.setTradeAcco(profit.getTradeAcco());
        // 基金代码
        assetFundModel.setFundCode(profit.getFundCode());
        // 基金名称
        assetFundModel.setFundName(fundNetValue.getChiNameAbbr());
        // 基金份额
        assetFundModel.setCurrentShares(cdUserShare.getCurrentShare());
        // 可用份额
        assetFundModel.setEnableShares(cdUserShare.getEnableShares());
        // 单位净值
        assetFundModel.setNetValue(profit.getNetValue());
        // 单位净值日期
        assetFundModel.setNetValueDate(fundNetValue.getTradingDay());
        result.setNetValueDate(fundNetValue.getTradingDay());
        // 资产类型
        assetFundModel.setAssetType(GlobalConstant.ASSET_TYPE_FUND);
        // 累积收益
        assetFundModel.setTotalAccumIncome(profit.getAccumulateProfitValue());
        // 区分货币基金的收益
        CalculateAssetsUtils.setIncome(fundNetValue, profit.getFundCode(), assetFundModel, lookups);
        // 当日收益
        assetFundModel.setTotalTodayIncome(profit.getProfitValue());
    }

    private PortfolioModel extractPortfolioByTrade(PortfolioModel portfolioModel, List<Lookup> lookups) {
        List<AssetFundModel> portfolioFunds1 = portfolioModel.getPortfolioFunds();
        List<PortfolioTradeModel> portfolioTrades = new ArrayList<>();
        List<AssetFundModel> portfolioFunds = new ArrayList<>();
        BigDecimal enableShare = new BigDecimal(0);
        BigDecimal currentShare = new BigDecimal(0);
        BigDecimal totalWorthValue = new BigDecimal(0);
        PortfolioTradeModel portfolioTradeModel = new PortfolioTradeModel();
        for (AssetFundModel assetFundModel : portfolioFunds1) {
            FundNetValueResult netValueResult = fundDetailService.getFundNetValue(assetFundModel.getFundCode(), DateUtils.addDay(new Date(), -1));
            currentShare = MoneyUtils.add(currentShare, assetFundModel.getCurrentShares());
            enableShare = MoneyUtils.add(enableShare, assetFundModel.getEnableShares());
            BigDecimal worthValue = enableShare.multiply(netValueResult.getUnitNV());
            worthValue = worthValue.setScale(2, BigDecimal.ROUND_HALF_UP);
            totalWorthValue = MoneyUtils.add(totalWorthValue, worthValue);

            AssetFundModel assetFundModels = new AssetFundModel();
            //基金代码
            assetFundModels.setFundCode(assetFundModel.getFundCode());
            //基金份额
            assetFundModels.setCurrentShares(assetFundModel.getCurrentShares());
            //可用份额
            assetFundModels.setEnableShares(assetFundModel.getEnableShares());
            // 单位净值
            assetFundModels.setNetValue(netValueResult.getUnitNV());
            //基金名称
            assetFundModels.setFundName(netValueResult.getChiNameAbbr());
            // 单位净值日期
            assetFundModels.setNetValueDate(netValueResult.getTradingDay());
            // 资产类型
            assetFundModels.setAssetType(GlobalConstant.ASSET_TYPE_FUND);
            //区分货币基金的收益
            CalculateAssetsUtils.setIncome(netValueResult, assetFundModels.getFundCode(), assetFundModels, lookups);
            assetFundModels.setTotalWorthValue(worthValue);
            portfolioFunds.add(assetFundModels);
        }
        for (AssetFundModel assetFundModel : portfolioFunds) {
            BigDecimal rate = assetFundModel.getTotalWorthValue().divide(totalWorthValue, 4, ROUND_HALF_DOWN);
            assetFundModel.setInvestRate(rate);
        }
        portfolioTradeModel.setCurrentShare(currentShare);
        portfolioTradeModel.setEnableShare(enableShare);
        portfolioTradeModel.setTotalWorthValue(totalWorthValue);
        portfolioTradeModel.setTradeAcco(portfolioModel.getTradeAcco());
        portfolioTradeModel.setPortfolioFunds(portfolioFunds);
        portfolioTradeModel.setPortfolioCode(portfolioModel.getPortfolioCode());
        portfolioTrades.add(portfolioTradeModel);
        portfolioModel.setPortfolioTrades(portfolioTrades);
        return portfolioModel;
    }


    /**
     * 查询组合列表
     *
     * @param userId
     * @return
     */
    @Override
    public AssetsPortfolioResult queryPortfolioList(Long userId) {
        AssetsPortfolioResult assetsPortfolioResult = new AssetsPortfolioResult();
        User user = userDao.getEntity(userId);
        List<Lookup> lookups = lookupDao.getLookupByType(RuleConstant.RULE_LOOKUP_TYPE_T0FUND);
        assetsPortfolioResult = BaseResultUtil.isOpen(assetsPortfolioResult, user);
        if (!assetsPortfolioResult.getSuccess()) {
            return assetsPortfolioResult;
        }
        // 用户持有的组合
        List<PortfolioModel> portfolioModels = new ArrayList<>();
        //查出所有 收益 放入map 为了速度优化   然后为了防止货币基金收益迟到的问题  所以只能倒序再过滤
        List<Profit> portfolioProfits = profitDao.selectNewPortfolioProfit(userId.intValue(), user.getExternalClientId(), getOldDate());
        Map<String, Profit> profitMap = new HashMap<>();
        for (Profit profit : portfolioProfits) {
            if (profitMap.get(profit.getTradeAcco() + profit.getFundCode()) != null) {
                continue;
            }
            profitMap.put(profit.getTradeAcco() + profit.getFundCode(), profit);
        }
        Map<String, List<Profit>> map = new HashMap<>();
        for (String p : profitMap.keySet()) {
            Profit profit = profitMap.get(p);
            if (map.get(profit.getTradeAcco()) != null) {
                List<Profit> profits = map.get(profit.getTradeAcco());
                profits.add(profit);
                map.put(profit.getTradeAcco(), profits);
            } else {
                List<Profit> profits = new ArrayList<>();
                profits.add(profit);
                map.put(profit.getTradeAcco(), profits);
            }
        }
        List<CdUserShare> portfolioShare = cdUserShareDao.selectNewPortfolioShare(userId.intValue(), user.getExternalClientId());
        Map<String, CdUserShare> shareMap = new HashMap<>();
        for (CdUserShare share : portfolioShare) {
            if (shareMap.get(share.getTradeAcco() + share.getFundCode()) != null) {
                continue;
            }
            shareMap.put(share.getTradeAcco() + share.getFundCode(), share);
        }
        List<PortfolioTradeAcco> portfolioTradeAccounts = portfolioTradeAccoDao.selectPortfolioTradeAccoByUserId(userId);
        for (PortfolioTradeAcco tradeAccount : portfolioTradeAccounts) {
            if (!GlobalConstant.PORTFOLIO_CODE_ONE.equals(tradeAccount.getPortfolioCode()) &&
                !GlobalConstant.PORTFOLIO_CODE_TWO.equals(tradeAccount.getPortfolioCode()) &&
                !GlobalConstant.PORTFOLIO_CODE_THREE.equals(tradeAccount.getPortfolioCode())) {
                continue;
            }
            PortfolioModel portfolioModel = new PortfolioModel();
            // 通过查询用户持有组合的编码，去查询对应组合所有信息
            setPortfolioMainInfo(userId, tradeAccount.getPortfolioCode(), portfolioModel, lookups, user, map, shareMap, tradeAccount.getPortfolioTradeAcco());
            // 设置组合模型次要信息，组合名称 是否可以调仓
            setPortfolioOthersInfo(userId, portfolioModel);
            // 在途
            TradeOrders tradeOrders = TradeOrders.builder()
                .userId(userId.intValue())
                .tradeAcco(tradeAccount.getPortfolioTradeAcco())
                .taconfirmFlag(GlobalConstant.TACONFIRM_FLAG_UNCONFIRM)
                .build();
            List<TradeOrders> tradeOrdersList = tradeOrdersDao.selectSellUnConfirmTrade(tradeOrders);
            List<String> portfolioAllotNo = new ArrayList<>();
            Integer sellInTransit = 0;
            for (TradeOrders to : tradeOrdersList) {
                if (!portfolioAllotNo.contains(to.getPortfolioAllotNo())) {
                    sellInTransit++;
                    portfolioAllotNo.add(to.getPortfolioAllotNo());
                }
            }

            //Integer sellInTransit = CalculateAssetsUtils.numOfSellInTransitPortfolio(applys, lookups, null, portfolioModel.getPortfolioCode());
            portfolioModel.setSellInTransit(sellInTransit);
            portfolioModels.add(portfolioModel);
        }
        TradeOrders tradeOrders = TradeOrders.builder().userId(userId.intValue()).build();
        List<TradeOrders> tradeOrdersList = tradeOrdersDao.selectBuyUnConfirmPortfolioTrade(tradeOrders);
        List<String> portfolioAllotNo = new ArrayList<>();
        Integer sellInTransit = 0;
        BigDecimal amount = new BigDecimal(0);
        for (TradeOrders to : tradeOrdersList) {
            if (!portfolioAllotNo.contains(to.getPortfolioAllotNo())) {
                sellInTransit++;
                portfolioAllotNo.add(to.getPortfolioAllotNo());
            }
            amount = MoneyUtils.add(amount, to.getBalance());
        }
        Boolean isInTransit = false;
        if (sellInTransit > 0) {
            isInTransit = true;
        }
        //AssetPortfolioModel assetPortfolioForInTransit = CalculateAssetsUtils.extractInTransit(lookups, applys, applyPortfolioCode);

        BigDecimal portfolioWorthValue = new BigDecimal(0);
        BigDecimal portfolioTodayIncome = new BigDecimal(0);
        BigDecimal portfolioAccumIncome = new BigDecimal(0);
        for (PortfolioModel portfolioModel : portfolioModels) {

            portfolioWorthValue = MoneyUtils.add(portfolioWorthValue, portfolioModel.getPortfolioWorthValue());
            portfolioTodayIncome = MoneyUtils.add(portfolioTodayIncome, portfolioModel.getPortfolioTodayIncome());
            portfolioAccumIncome = MoneyUtils.add(portfolioAccumIncome, portfolioModel.getPortfolioAccumIncome());
            assetsPortfolioResult.setNetValueDate(portfolioModel.getNetValueDate());
        }
        assetsPortfolioResult.setInTransitAmount(amount);
        assetsPortfolioResult.setInTransit(isInTransit);
        assetsPortfolioResult.setInTransitNum(sellInTransit);
        assetsPortfolioResult.setPortfolioWorthValue(MoneyUtils.add(portfolioWorthValue, amount));
        assetsPortfolioResult.setPortfolioTodayIncome(portfolioTodayIncome);
        assetsPortfolioResult.setPortfolioAccumIncome(portfolioAccumIncome);
        assetsPortfolioResult.setPortfolios(portfolioModels);
        return assetsPortfolioResult;
    }

    /**
     * 总资产查组合
     *
     * @param userId
     * @return
     */
    @Override
    public AssetsPortfolioResult queryPortfolioListForAssets(Long userId) {
        AssetsPortfolioResult assetsPortfolioResult = new AssetsPortfolioResult();
        User user = userDao.getEntity(userId);
        List<Lookup> lookups = lookupDao.getLookupByType(RuleConstant.RULE_LOOKUP_TYPE_T0FUND);
        assetsPortfolioResult = BaseResultUtil.isOpen(assetsPortfolioResult, user);
        if (!assetsPortfolioResult.getSuccess()) {
            return assetsPortfolioResult;
        }
//        Map<String, Object> map = tradeApplyQueryService.query(GlobalConstant.MAX_REQUEST_NUM, 1, 1, "1", "",
//            user.getExternalClientId(), "", "", "", GlobalConstant.TACONFIRM_FLAG_UNCONFIRM, "", "", "", "", "",
//            "", "", "");
//
//        // 查询结果
//        List<Map<String, Object>> list = new ArrayList<>();
//        HundsunUtils.ConvertToList(map, list, assetsPortfolioResult);
//        if (!assetsPortfolioResult.getSuccess()) {
//            return assetsPortfolioResult;
//        }
//        ApplyListResult applyListResult = new ApplyListResult();
        //List<ApplyModel> applys = ModelPopulateUtils.populateApply(list, applyListResult, null, null);
        //List<String> applyPortfolioCode = new ArrayList<>();
//        for (ApplyModel applyModel : applys) {
//            if (!Strings.isNullOrEmpty(applyModel.getPortfolioCode()) && !applyPortfolioCode.contains(applyModel.getPortfolioCode())) {
//                applyPortfolioCode.add(applyModel.getPortfolioCode());
//            }
//        }
        // 用户持有的组合
        List<PortfolioModel> portfolioModels = new ArrayList<>();
        //查出所有 收益 放入map 为了速度优化   然后为了防止货币基金收益迟到的问题  所以只能倒序再过滤
        List<Profit> portfolioProfits = profitDao.selectNewPortfolioProfit(userId.intValue(), user.getExternalClientId(), getOldDate());
        Map<String, Profit> profitMap = new HashMap<>();
        for (Profit profit : portfolioProfits) {
            if (profitMap.get(profit.getTradeAcco() + profit.getFundCode()) != null) {
                continue;
            }
            profitMap.put(profit.getTradeAcco() + profit.getFundCode(), profit);
        }
        Map<String, List<Profit>> map = new HashMap<>();
        for (String p : profitMap.keySet()) {
            Profit profit = profitMap.get(p);
            if (map.get(profit.getTradeAcco()) != null) {
                List<Profit> profits = map.get(profit.getTradeAcco());
                profits.add(profit);
                map.put(profit.getTradeAcco(), profits);
            } else {
                List<Profit> profits = new ArrayList<>();
                profits.add(profit);
                map.put(profit.getTradeAcco(), profits);
            }
        }
        List<CdUserShare> portfolioShare = cdUserShareDao.selectNewPortfolioShare(userId.intValue(), user.getExternalClientId());
        Map<String, CdUserShare> shareMap = new HashMap<>();
        for (CdUserShare share : portfolioShare) {
            if (shareMap.get(share.getTradeAcco() + share.getFundCode()) != null) {
                continue;
            }
            shareMap.put(share.getTradeAcco() + share.getFundCode(), share);
        }
        List<PortfolioTradeAcco> portfolioTradeAccounts = portfolioTradeAccoDao.selectPortfolioTradeAccoByUserId(userId);

        for (PortfolioTradeAcco tradeAccount : portfolioTradeAccounts) {
            if (!GlobalConstant.PORTFOLIO_CODE_ONE.equals(tradeAccount.getPortfolioCode()) &&
                !GlobalConstant.PORTFOLIO_CODE_TWO.equals(tradeAccount.getPortfolioCode()) &&
                !GlobalConstant.PORTFOLIO_CODE_THREE.equals(tradeAccount.getPortfolioCode())) {
                continue;
            }
            PortfolioModel portfolioModel = new PortfolioModel();
            // 通过查询用户持有组合的编码，去查询对应组合所有信息
            setPortfolioMainInfo(userId, tradeAccount.getPortfolioCode(), portfolioModel, lookups, user, map, shareMap, tradeAccount.getPortfolioTradeAcco());
            portfolioModels.add(portfolioModel);
        }
        TradeOrders tradeOrders = TradeOrders.builder().userId(userId.intValue()).build();
        List<TradeOrders> tradeOrdersList = tradeOrdersDao.selectBuyUnConfirmPortfolioTrade(tradeOrders);
        List<String> portfolioAllotNo = new ArrayList<>();
        Integer sellInTransit = 0;
        BigDecimal amount = new BigDecimal(0);
        for (TradeOrders to : tradeOrdersList) {
            if (!portfolioAllotNo.contains(to.getPortfolioAllotNo())) {
                sellInTransit++;
                portfolioAllotNo.add(to.getPortfolioAllotNo());
            }
            amount = MoneyUtils.add(amount, to.getBalance());
        }
        Boolean isInTransit = false;
        if (sellInTransit > 0) {
            isInTransit = true;
        }
        //AssetPortfolioModel assetPortfolioForInTransit = CalculateAssetsUtils.extractInTransit(lookups, applys, applyPortfolioCode);

        BigDecimal portfolioWorthValue = new BigDecimal(0);
        BigDecimal portfolioTodayIncome = new BigDecimal(0);
        BigDecimal portfolioAccumIncome = new BigDecimal(0);
        for (PortfolioModel portfolioModel : portfolioModels) {

            portfolioWorthValue = MoneyUtils.add(portfolioWorthValue, portfolioModel.getPortfolioWorthValue());
            portfolioTodayIncome = MoneyUtils.add(portfolioTodayIncome, portfolioModel.getPortfolioTodayIncome());
            portfolioAccumIncome = MoneyUtils.add(portfolioAccumIncome, portfolioModel.getPortfolioAccumIncome());
            assetsPortfolioResult.setNetValueDate(portfolioModel.getNetValueDate());
        }
        assetsPortfolioResult.setInTransitAmount(amount);
        assetsPortfolioResult.setInTransit(isInTransit);
        assetsPortfolioResult.setInTransitNum(sellInTransit);
        assetsPortfolioResult.setPortfolioWorthValue(MoneyUtils.add(portfolioWorthValue, amount));
        assetsPortfolioResult.setPortfolioTodayIncome(portfolioTodayIncome);
        assetsPortfolioResult.setPortfolioAccumIncome(portfolioAccumIncome);
        assetsPortfolioResult.setPortfolios(portfolioModels);
        return assetsPortfolioResult;
    }

    /**
     * 查询个人总资产
     *
     * @param userId
     * @return
     */
    @Override
    public AssetsResult queryAssets(Long userId) {
        AssetsResult assetsResult = new AssetsResult();
        // 计算组合资产
        AssetsPortfolioResult assetsPortfolioResult = queryPortfolioList(userId);
        AssetPortfolioModel assetPortfolioModel = new AssetPortfolioModel();
        // 涉及多个接口返回模型问题，暂时只能这样，如果需要改动可能涉及前端修改
        BeanUtils.copyProperties(assetsPortfolioResult, assetPortfolioModel);
        assetPortfolioModel.setPortfolioNum(assetPortfolioModel.getPortfolios().size());
        // 组合
        assetsResult.setPortfolios(assetPortfolioModel);
        // 瑞福宝
        WalletDetailResultV2 walletList = null;
        try {
            walletList = getWalletList(userId);
        } catch (BaseAppException e) {
            assetsResult.setSuccess(false);
            e.printStackTrace();
            log.warn("瑞福宝本地化数据查询异常！");
        }
        assert walletList != null;
        getWalletAssets(assetsResult, walletList);
        // 计算普通基金
        ShareListResult allShares = null;
        try {
            allShares = getAllShares(userId, GlobalConstant.MAX_REQUEST_NUM, 0);
        } catch (BaseAppException e) {
            e.printStackTrace();
            assetsResult.setSuccess(false);
            log.warn("基金本地化数据查询异常！");
        }
        assert allShares != null;
        getNormalAssets(assetsResult, allShares);

        // 瑞福宝  +  基金  +  组合
        BigDecimal walletTotalAccumIncome = assetsResult.getWallet().getTotalAccumIncome();
        BigDecimal fundTotalAccumIncome = assetsResult.getFund().getTotalAccumIncome();
        BigDecimal portfolioAccumIncome = assetsResult.getPortfolios().getPortfolioAccumIncome();
        assetsResult.setTotalAccumIncome(MoneyUtils.add(MoneyUtils.add(walletTotalAccumIncome, fundTotalAccumIncome), portfolioAccumIncome));

        BigDecimal walletTotalWorthValue = assetsResult.getWallet().getTotalWorthValue();
        BigDecimal portfolioWorthValue = assetsResult.getPortfolios().getPortfolioWorthValue();
        BigDecimal fundTotalWorthValue = assetsResult.getFund().getTotalWorthValue();
        assetsResult.setTotalWorthValue(MoneyUtils.add(MoneyUtils.add(walletTotalWorthValue, fundTotalWorthValue), portfolioWorthValue));

        BigDecimal fundTodayIncome = assetsResult.getFund().getTotalTodayIncome();
        BigDecimal portfolioTodayIncome = assetsResult.getPortfolios().getPortfolioTodayIncome();
        BigDecimal walletTotalTodayIncome = assetsResult.getWallet().getTotalTodayIncome();
        assetsResult.setTotalTodayIncome(MoneyUtils.add(fundTodayIncome, MoneyUtils.add(walletTotalTodayIncome, portfolioTodayIncome)));

        BigDecimal walletInTransitAmount = assetsResult.getWallet().getInTransitAmount();
        BigDecimal portInTransitAmount = assetsResult.getPortfolios().getInTransitAmount();
        BigDecimal fundInTransitAmount = assetsResult.getFund().getInTransitAmount();
        assetsResult.setTotalInTransitAmount(MoneyUtils.add(walletInTransitAmount, MoneyUtils.add(fundInTransitAmount, portInTransitAmount)));

        return assetsResult;
    }

    /**
     * 计算基金
     *
     * @param assetsResult
     * @param allShares
     */
    @Override
    public void getNormalAssets(AssetsResult assetsResult, ShareListResult allShares) {
        List<ShareModel> shares = allShares.getShares();
        List<AssetFundModel> fundModels = new ArrayList<>();
        for (ShareModel share : shares) {
            AssetFundModel assetFundModel = new AssetFundModel();
            assetFundModel.setAppFundType(share.getAppFundType());
            assetFundModel.setCost(share.getCost());
            assetFundModel.setCurrentShares(share.getCurrentShare());
            assetFundModel.setDailyProfit(share.getDailyProfit());
            assetFundModel.setDividends(share.getDividends());
            assetFundModel.setEnableShares(share.getEnableShares());
            assetFundModel.setFundCode(share.getFundCode());
            assetFundModel.setNetValue(share.getNetValue());
            assetFundModel.setNetValueDate(share.getNetValueDate());
            assetFundModel.setSellInTransit(share.getSellInTransit());
            assetFundModel.setTotalTodayIncome(share.getTodayIncome());
            assetFundModel.setTotalWorthValue(share.getWorthValue());
            assetFundModel.setTradeAcco(share.getTradeAccount());
            assetFundModel.setTotalAccumIncome(share.getTotalAccumIncome());
            fundModels.add(assetFundModel);
        }
        AssetFundModel assetFundModel = new AssetFundModel();
        assetFundModel.setFundModelList(fundModels);
        assetFundModel.setNetValueDate(allShares.getNetValueDate());
        assetFundModel.setFundsCount(fundModels.size());
        assetFundModel.setTotalAccumIncome(allShares.getTotalAccumIncome());
        assetFundModel.setTotalWorthValue(allShares.getTotalWorthValue());
        assetFundModel.setTotalTodayIncome(allShares.getTotalTodayIncome());
        assetFundModel.setInTransitNum(allShares.getTotalNumInTransit());
        assetFundModel.setInTransitAmount(allShares.getTotalInTransit());
        boolean inTransit = false;
        if (allShares.getTotalNumInTransit() > 0) {
            inTransit = true;
        }
        assetFundModel.setInTransit(inTransit);
        assetsResult.setFund(assetFundModel);
    }

    /**
     * 计算瑞福宝
     */
    private void getWalletAssets(AssetsResult assetsResult, WalletDetailResultV2 walletList) {

        List<AssetFundModel> fundModelList = walletList.getFundModelList();
        AssetFundModel assetFundModel = new AssetFundModel();
        assetFundModel.setFundModelList(fundModelList);
        assetFundModel.setFundsCount(fundModelList.size());
        boolean inTransit = false;

        BigDecimal totalAccumIncome = new BigDecimal(0);
        for (AssetFundModel fundModel : fundModelList) {
            totalAccumIncome = MoneyUtils.add(totalAccumIncome, fundModel.getTotalAccumIncome());
        }
        if (walletList.getInTransitNum() > 0) {
            inTransit = true;
        }
        // 是否有在途
        assetFundModel.setInTransit(inTransit);
        // 在途
        assetFundModel.setInTransitNum(walletList.getInTransitNum());
        assetFundModel.setInTransitAmount(walletList.getInTransitAmount());

        assetFundModel.setTotalTodayIncome(walletList.getTti());
        assetFundModel.setTotalWorthValue(walletList.getTwv());
        assetFundModel.setTotalAccumIncome(totalAccumIncome);

        assetFundModel.setNetValueDate(walletList.getNetValueDate());
        assetFundModel.setInTransit(inTransit);
        assetsResult.setWallet(assetFundModel);
    }

    //获取当前日期 前12天的日期
    private String getOldDate() {
        String d = DateUtils.dateToSimpleStr(DateUtils.addDay(new Date(), -12));
        return d;
    }
}
